#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "main.h"
#include "mainlogic.h"
#include "ocxo_ct.h"
#include "config.h"
#include "ocxo_ct.h"
#include "Utility.h"
#include "spi_flash.h"
#include "DBG.h"

extern UartBuf cmdBuf;
extern UART_HandleTypeDef huart1;

void CMD_Parse(char *buf, uint32_t len);

char g_uart_input[256];

void Uart_ReceiveProcess(void)
{
	static int cur_idx = 0;
	
	if(cmdBuf.lineEnd != cmdBuf.lineStart)
	{
		//printf("debug s=%d e=%d\n", cmdBuf.lineEnd, cmdBuf.lineStart);
		__disable_irq();
		uint16_t tmpEnd = cmdBuf.lineEnd;
		__enable_irq();
		uint8_t tmp;
		while(tmpEnd != cmdBuf.lineStart)
		{
			tmp = cmdBuf.line[cmdBuf.lineStart++];
			if(tmp == 0)
			{
				continue;
			}
			g_uart_input[cur_idx++] = tmp;
			//printf("%c cd=%d %d ", tmp, tmp, cur_idx);
			if(cmdBuf.lineStart >= cmdBuf.lineLen)
			{
				cmdBuf.lineStart = 0;
			}
			if(cur_idx >= 250) {
				cur_idx = 0;
				break;
			}
			if(tmp == '\n' || tmp == '\r')
			{
				g_uart_input[cur_idx] = 0;
				char *p = g_uart_input;
				int i=0;
				for(i=0;i<cur_idx;i++)
				{
					if(*p == '$')
						break;
					else
						p++;
				}
				if((cur_idx-i)>1)
				{
					CMD_Parse(p, cur_idx-i);
				}
				cur_idx = 0;
				break;
			}
		}
		//printf("\n");
	}
}

void CMD_ParseOptions(char **options, int size)
{
  for (int i = 0; i < size; i++)
  {
    char *cmd[2];
    char *tmpstr = strtok(options[i], "=");
    int ct = 0;
    while (tmpstr != NULL)
    {
      cmd[ct++] = tmpstr;
      if (ct >= 2)
      {
        break;
      }
      tmpstr = strtok(NULL, " ");
    }
    if (ct >= 1)
    {
			uint8_t lite = 0;
			if(!strcmp(cmd[0],"detect")) {
				int t = atoi(cmd[1]);
				if(t>=1 && t<=100000) {
					ocxo_doDetectCmd(t);
				}
			}
			else if(!strcmp(cmd[0],"reset"))
			{
				__set_FAULTMASK(1);
				NVIC_SystemReset();
			}
			else if(!strcmp(cmd[0],"ocxoWarm")) {
				int t = atoi(cmd[1]);
				if(t>=10 && t<=10000) {
					g_Controller_config.ocxoWarm = t;
					Controller_Config_Save();
				}
			}
			else if(!strcmp(cmd[0],"stopControl")) {
				int t = atoi(cmd[1]);
				Stop_OC_Control(t);
			}
			else if(!strcmp(cmd[0],"boardtype")) {
				int t = atoi(cmd[1]);
				g_Controller_config.type = t;
				Controller_Config_Save();
			}
			else if(!strcmp(cmd[0],"ocxoformat")) {
				CMD_FormatOcxo();
			}
			else if(!strcmp(cmd[0],"ocxoinfo")) {
				if(cmd[1] && cmd[1][0])
				{
					strncpy(g_Ocxo_info.ocxo_info, cmd[1], 15);
					OcxoInfo_Save();
				}
			}
			else if(!strcmp(cmd[0],"ocxoage")) {
				int tmp = atoi(cmd[1]);
				if(tmp > 1)
				{
					g_Ocxo_info.ocxo_agetime = tmp;
					OcxoInfo_Save();
				}					
			}
			else if(!strcmp(cmd[0],"Noise")) {
				double t = strtod(cmd[1],NULL);
				if(t>=0.1 && t<=200) {
					g_Ocxo_info.lowNoise = t;
					OcxoInfo_Save();
				}
			}
			else if(!strcmp(cmd[0],"dac")) {
				char *opt[5];
				int size = 0;
	      ParseCmd(cmd[1], opt, 5, &size, "#");
				uint32_t dacHigh = atoi(opt[0]);
				uint32_t dacLow = atoi(opt[1]);
				if(dacHigh < 1000 && dacLow < 10000)
				{
					setDacValue((dacHigh<<7)+dacLow, 0);
				}
				else
				{
					DBGI("bad par %d %d\n", dacHigh, dacLow);
				}
			}
			else if(!strcmp(cmd[0],"dacdir")) {
				char *opt[5];
				int size = 0;
	      ParseCmd(cmd[1], opt, 5, &size, "#");
				uint32_t dacHigh = atoi(opt[0]);
				uint32_t dacLow = atoi(opt[1]);
				if(dacHigh < 65535 && dacLow < 10000)
				{
					setDacValueDirect(dacHigh,dacLow);
				}
				else
				{
					DBGI("bad par %d %d\n", dacHigh, dacLow);
				}
			}
			else if(!strcmp(cmd[0],"dacOffset")) {
				int tmp = atoi(cmd[1]);
				if(ABS(tmp) < 2000)
				{
					g_Controller_config.dacOffset = tmp;
					Controller_Config_Save();
				}					
			}
			else if(!strcmp(cmd[0],"center")) {
				int tmp = atoi(cmd[1]);
				if(tmp < 1000000 && tmp > 0)
				{
					g_Ocxo_info.dacValue = tmp;
					OcxoInfo_Save();
				}					
			}
			else if(!strcmp(cmd[0],"printOcxo")) {
					CMD_PrintOcxo();
			}
			else if(!strcmp(cmd[0],"printConfig")) {
					CMD_PrintConfig();
			}
			else if(!strcmp(cmd[0],"gps")) {
				uint32_t time = mktime(g_gpsStatus.year, g_gpsStatus.month, g_gpsStatus.day, 
					g_gpsStatus.hour,g_gpsStatus.min, g_gpsStatus.sec);
				time += 8*60*60;
				Calendar_Structure datetime;
				TimestampToNormalTime(&datetime, time);
				DBGI("lat=%lf lon=%lf sat=%d %d-%02d-%02d %02d:%02d:%02d\n", g_gpsStatus.lat, g_gpsStatus.lon, 
					g_gpsStatus.satCount, datetime.year, datetime.month, datetime.day, datetime.hour, 
					datetime.min, datetime.second);
			}
			else if(!strcmp(cmd[0],"format")) {
				DBGI("format all spi flash.\n");
				SPI_Flash_EraseTotal();
			}
			else if(!strcmp(cmd[0],"spilog"))
			{
				char *opt[5];
				int size = 0;
	      		ParseCmd(cmd[1], opt, 5, &size, "#");
				if(size == 2)
				{
					int start = atoi(opt[0]);
					int end = atoi(opt[1]);
					ocxo_logshow(start, end);
				}
			}
			else if(!strcmp(cmd[0],"spilogage"))
			{
				int t = atoi(cmd[1]);
				if(t>=1)
				{
					ocxo_showlog_age(t);
				}
			}
			else if(!strcmp(cmd[0],"10minFixRate")) {
				double t = strtod(cmd[1],NULL);
				if(t>=1 && t<=400) {
					g_Controller_config.offsetFix = t;
					Controller_Config_Save();
				}
			}
			else if(!strcmp(cmd[0],"oc_temp")) {
				double t = strtod(cmd[1],NULL);
				if(ABS(t)<=5000) {
					g_Ocxo_info.temp = t;
					OcxoInfo_Save();
				}
			}
			else if(!strcmp(cmd[0],"printHistory")) {
				cmd_showHistoryLog();
			}
			else if(!strcmp(cmd[0],"oc_adj")) {
				double t = strtod(cmd[1],NULL);
				if(ABS(t)<=20) {
					g_Ocxo_info.adj_step = t;
					OcxoInfo_Save();
				}
			}
			else if(!strcmp(cmd[0],"qError")) {
				int t = atoi(cmd[1]);
			  	g_Controller_config.qError = t;
				Controller_Config_Save();
			}
			else if(!strcmp(cmd[0],"fullscal")) {
				int t = atoi(cmd[1]);
			  g_Controller_config.fullscal = t;
				Controller_Config_Save();
			}
			else if(!strcmp(cmd[0],"adminmax")) {
				ShowADMinMax();
			}
			else if(!strcmp(cmd[0],"adczero")) {
				int t = atoi(cmd[1]);
				if(t > 0)
				{
					g_Controller_config.adcZero = t;
					Controller_Config_Save();
				}
			}
			else if(!strcmp(cmd[0],"tdctime")) {
				int t = atoi(cmd[1]);
				if(t > 0 && t<=60000)
				{
					g_Controller_config.tdctime = t;
					Controller_Config_Save();
				}
			}
			else if(!strcmp(cmd[0],"qLong")) {
				int t = atoi(cmd[1]);
			  g_Controller_config.qLongFix = t;
				Controller_Config_Save();
			}
			else if(!strcmp(cmd[0],"qLongValue")) {
				int t = atoi(cmd[1]);
			  g_Controller_config.qLongValue = t;
				Controller_Config_Save();
			}
			else if(!strcmp(cmd[0],"statusled")) {
				int t = atoi(cmd[1]);
				if(t)
				{
					HAL_GPIO_WritePin(STATUS_GPIO_Port, STATUS_Pin, GPIO_PIN_SET);
				}
				else
				{
					HAL_GPIO_WritePin(STATUS_GPIO_Port, STATUS_Pin, GPIO_PIN_RESET);
				}
			}
			else{
				DBGI("unknow cmd %s\n", cmd[0]);
			}
			if(lite == 0)
			{
				DBGI("cmd=%s value=%s\n", cmd[0], cmd[1]);
			}
			else
			{
				DBGI("cmd=%s\n",cmd[0]);
			}
    }
  }
}

void CMD_Parse(char *buf, uint32_t len)
{
  int end = 0;
  int start = 0;
  int i = start;
  //寻找命令起始位置
  for (; i < len; i++)
  {
    if ((buf[i] != '\r') && (buf[i] != '\n'))
    {
      start = i;
      break;
    }
  }
	//寻找结束位置
  for (; i < len; i++)
  {
    if ((buf[i] == '\r') || (buf[i] == '\n'))
    {
      end = i;
      break;
    }
  }
  if (start < end)
  {
		if(buf[start] == '$')
		{
			start += 1;
			buf[end] = 0;
			char *options[20];
			int ct_opt = 0;
			//分割字符串
			char *tmpstr = strtok(buf + start, " ");
			while (tmpstr != NULL)
			{
				options[ct_opt++] = tmpstr;
				if (ct_opt >= 20)
				{
					break;
				}
				tmpstr = strtok(NULL, " ");
			}
			//处理配置数组
			CMD_ParseOptions(options, ct_opt);
		}
		else
		{
			if(buf[start] != ';')
			{
				buf[end] = 0;
				printf(";%s\n",buf+start);
			}
		}
  }
	//将处理后的缓存清空
  start = end + 1;
  for (i = start; i < len; i++)
  {
    if ((buf[i] != '\r') && (buf[i] != '\n'))
    {
      break;
    }
  }
  start = 0;
  char haveNewLine = 0;
  for (; i < len; i++)
  {
    buf[start++] = buf[i];
    if ((buf[i] == '\r') || (buf[i] == '\n'))
    {
      haveNewLine = 1;
    }
  }
  buf[start] = 0;
	//如果还有完整的命令行,递归调用
  if (haveNewLine)
  {
    CMD_Parse(buf,start);
  }
}
